package com.meter.data;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

/**
 * @author 杨健
 * @since 2019/6/20 11:32
 */
public class DBDataGetter {
    //用于储存配置文件
    private static Properties properties=new Properties();
    //类加载的时候加载配置文件
    static{
        InputStream resourceAsStream = com.meter.data.DBDataGetter.class.getResourceAsStream("/jdbcSqlServer.properties");
        try {
            properties.load(resourceAsStream);
            resourceAsStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 该方法要连接数据库的地址、用户名、用户密码在meterDBConfig.properties文件中进行配置，并且返回的连接对象是默认不进行自动提交
     *
     * @return 返回一个java.sql.Connection类型的数据库连接对象用于进行数据库的连接
     */
    private static Connection getConnection() {
        Connection connection = null;
        try {
            // 加载数据库的驱动程序
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            // 数据库的连接地址
            StringBuilder dburl = new StringBuilder();
            dburl.append(properties.getProperty("db.url"));

            // 获取数据库连接
            connection = DriverManager.getConnection(dburl.toString(),
                    properties.getProperty("db.user"),
                    properties.getProperty("db.passwd"));
            // 经连接设置成非自动提交以方便进行出错时候的回滚
            connection.setAutoCommit(false);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return connection;
    }

    /**
     * 该方法用来执行不需要返回值的sql语句
     *
     * @param sql
     *            这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
     * @return 返回一个int类型的结果，该结果表示执行该语句之后受到影响的数据行数
     */
    public static int executeSqlWithoutResult(String sql) {
        // 保存执行语句影响到的行数
        int val = 0;
        // 保存一个处理语句
        Statement stm = null;
        // 获取一个数据库连接
        Connection connection = getConnection();
        try {
            // 判断连接是否为空防止发生NPE问题
            if (connection != null) {
                stm = connection.createStatement();
                // 判断处理是否为空防止发生NPE问题
                if (stm != null) {
                    // 执行sql语句并返回影响的行数
                    val = stm.executeUpdate(sql);
                    // 提交操作
                    connection.commit();
                }
            }
        } catch (SQLException e) {
            try {// 发生意外情况进行事务回滚
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            try {// 确保关闭处理语句和数据库连接
                stm.close();
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return val;
    }

    /**
     * 该方法用来执行需要返回结果的sql语句
     *
     * @param sql
     *            这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
     * @return 返回一个java.sql.ResultSet类型的结果，该结果表示执行该语句之后返回的结果集合
     * @throws SQLException
     */
    public static List<HashMap<String, String>> executeSqlWithResult(String sql) {
        // 保存执行语句后的返回结果集
        ResultSet resultSet = null;
        // 定义一个处理语句
        Statement stm = null;
        // 获取一个数据库连接
        Connection connection = getConnection();
        try {
            // 确保连接不为空防止发生NPE问题
            if (connection != null) {
                stm = connection.createStatement();
                // 确保处理语句不为空防止发生NPE问题
                if (stm != null) {
                    resultSet = stm.executeQuery(sql);
                    // 提交操作
                    connection.commit();
                }
            }
        } catch (SQLException e) {
            try {// 发生意外情况进行事务回滚
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        List<HashMap<String, String>> resloverResultSet = null;
        try {
            resloverResultSet = resloverResultSet(resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return resloverResultSet;
    }

    /**
     * 该方法用来执行需要返回结果的sql语句
     * @param sql 这是要执行的sql语句，方法内没有进行语法的监测传入前一定要进行语句的检查
     * @param pageNum 需要的页
     * @param pageSize 每页条数
     * @return 返回一个java.sql.ResultSet类型的结果，该结果表示执行该语句之后返回的结果集合
     */
    public static List<HashMap<String, String>> executeSqlWithResult(String sql,int pageNum,int pageSize) {
        // 保存执行语句后的返回结果集
        ResultSet resultSet = null;
        // 定义一个处理语句
        Statement stm = null;
        // 获取一个数据库连接
        Connection connection = getConnection();
        try {
            // 确保连接不为空防止发生NPE问题
            if (connection != null) {
                stm = connection.createStatement();
                // 确保处理语句不为空防止发生NPE问题
                if (stm != null) {
                    //添加分页部分
                    sql+=" OFFSET ("+(pageNum-1)*pageSize+") ROW FETCH NEXT "+pageSize+" rows only";
                    resultSet = stm.executeQuery(sql);
                    // 提交操作
                    connection.commit();
                }
            }
        } catch (SQLException e) {
            try {// 发生意外情况进行事务回滚
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
        List<HashMap<String, String>> resloverResultSet = null;
        try {
            resloverResultSet = resloverResultSet(resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return resloverResultSet;
    }

    /**
     *
     *
     * @param resultSet
     *            sql查询之后返回的结果集合类型为java.sql.ResultSet
     * @return 返回的list类型的结果集，结果集的元素为map类型的<K,V>对
     * @throws SQLException
     */
    private static List<HashMap<String, String>> resloverResultSet(ResultSet resultSet) throws SQLException {
        List<HashMap<String, String>> res = null;
        // 判断参数非空防止发生NPE问题
        if (resultSet != null) {
            res = new ArrayList<>();
            ResultSetMetaData m = resultSet.getMetaData();
            int columnCount = m.getColumnCount();
            while (resultSet.next()) {
                HashMap<String, String> map = new HashMap<>();
                for (int index = 1; index <= columnCount; index++) {
                    map.put(m.getColumnLabel(index), resultSet.getString(index));
                }
                res.add(map);
            }

        }
        return res;
    }
}
